/**
 *    @file       cmysql.h
 *
 *    @brief      
 *    @details
 *
 *    @version    1.0
 *    @date       12/19/2012 05:55:10 PM
 *
 *    @author     Theophilus (), wangtf418@gmail.com
 */
#ifndef _BF_CMYSQL_H_
#define _BF_CMYSQL_H_

#ifndef __WITHOUT_MYSQL_DB__
#include <mysql.h>
#include <string>
#include <map>
#include "comdef.h"
#include "comexception.h"
#include "threadmutex.h"

struct mysql_conf
{
	std::string m_host;
	std::string m_user;
	std::string m_passwd;

	mysql_conf()
	{

	}

	mysql_conf(const std::string &host, const std::string &user, const std::string &passwd)
		: m_host(host), m_user(user),m_passwd(passwd)
	{

	}

	mysql_conf(const mysql_conf &conf)
		: m_host(conf.m_host), m_user(conf.m_user), m_passwd(conf.m_passwd)
	{

	}
};

class mysql_exception : public comexception
{
public:
	mysql_exception()
	{

	}
	
	mysql_exception(const std::string &sql, const std::string &errmsg, bf_int_t err_no)
		: m_sql(sql), m_errmsg(errmsg), m_errno(err_no)
	{

	}

public:
	inline const std::string & get_sql()
	{
		return m_sql;
	}

	inline void set_sql(const std::string &sql)
	{
		m_sql = sql;
	}

protected:
	std::string m_sql;
	std::string m_errmsg;
	bf_int_t m_errno;
};

typedef unsigned long *MYSQL_ROWLEN;

class cmysql
{
public:
	cmysql();
	cmysql(const mysql_conf &conf);
	virtual ~cmysql();

public:
	bf_int_t init();
	bf_int_t connect(bf_uint_t connect_timeout = BF_UINT_MAX);
	bf_int_t connect(const mysql_conf &conf, bf_uint_t connect_timeout = BF_UINT_MAX);
	void close();

public:
	bf_int_t query(const std::string &sql);
	bf_int_t fetch_row();
	std::string get_fieldname(bf_uint_t field_index);
	bf_int_t get_field(const std::string &fieldname, std::string &filecontent_out);
	bf_char_t* get_field(const std::string &fieldname); //< not recommended, dangerous when field value is binary
	bf_ullong_t get_lastinsertid();
	void escape_string(std::string& str);
	bf_int_t set_option(enum mysql_option option, const bf_char_t *arg);
	bf_int_t set_option_connect_timeout(bf_uint_t connect_timeout);
	bf_int_t set_option_read_timeout(bf_uint_t read_timeout);
	bf_int_t set_option_write_timeout(bf_uint_t write_timeout);
	bf_int_t set_option_auto_reconnect(my_bool auto_connect_flag);

public:
	inline mysql_conf& get_conf()
	{
		return m_conf;
	}

	inline bf_ullong_t get_fieldnum()
	{
		return m_field_num;
	}

	inline bf_ullong_t get_rownum()
	{
		return m_row_num;
	}

	inline std::map<std::string, bf_uint_t>& get_fieldname()
	{
		return m_fieldnames;
	}

	inline void set_throw_exception(bf_int_t throw_flag = 1)
	{
		m_ifthrow = throw_flag;
	}

protected:
	bf_int_t store_result();
	void free_result();
	bf_int_t init_fieldname();
	void set_error(const std::string &errmsg, const std::string &sql, bf_int_t error_no);
	void throw_exception();

protected:
	MYSQL m_connection;
	mysql_conf m_conf;
	bf_int_t m_ifconnected;

protected:
	MYSQL_RES *m_result;
	MYSQL_ROW m_row;
	MYSQL_ROWLEN m_row_len;
	bf_uint_t m_field_num;
	bf_ullong_t m_row_num;
	std::map<std::string, bf_uint_t> m_fieldnames;
	mysql_exception m_error;
	volatile bf_int_t m_ifthrow;

protected:
	static threadmutex m_initlock;
};

#endif //endif ifndef __WITHOUT_MYSQL_DB__

#endif

